import inspect
def easy_call(f):
    import types
    s=0
    assert(callable(f) is True)
    if type(f) not in (types.FunctionType,types.MethodType):
        f=f.__call__
    assert(type(f) in (types.FunctionType,types.MethodType))
    #~ assert(type(f) in (types.FunctionType,types.MethodType))
    if type(f) is  types.MethodType:
        s=1
    elif type(f) is types.FunctionType:
        s=0
    else:
        raise Exception("What's Wrong")
    caller_frame=inspect.currentframe().f_back
    l=caller_frame.f_locals
    g=caller_frame.f_globals
    argspec=inspect.getfullargspec(f)
    assert(argspec.varargs is  None and argspec.varkw is None)
    div=len(argspec.defaults)
    args={}
    for i in argspec.args[s:div]:
        if i not in l and i not in g:
            raise Exception('"%s" must be define local or  global' % i)
        args[i]=l[i] if i in l else g[i]
    for i in argspec.args[div:]:
        if i not in l and i not in g:
            continue
        args[i]=l[i] if i in l else g[i]
    return f(**args)
import os,imp,sys
def import_ext(name,path='.'):
    if name in sys.modules:
        return sys.modules[name]
    f=os.path.join(*name.split('.'))
    (file, filename, data) = imp.find_module(f, [os.path.abspath(path)])
    #~ print(name, file, filename)
    return imp.load_module(name, file, filename, data)

def execfile(fname,g=None,l=None):
    caller_frame=get_caller_frame()
    if type(g) is not dict :
        g=caller_frame.f_globals
    if type(l) is not dict :
        l=caller_frame.f_locals
    with open(fname,'r') as f:
        code = compile(f.read(), fname, 'exec')
        g['__file__']=fname
        exec(code, g,l )

def available_modules(root_path):
    root_path=os.path.abspath(root_path)
    sep=os.path.sep
    len_root_path=len(root_path.split(sep))
    for root,sub,files in os.walk(root_path):
        if '__init__.py' not in files:
            continue
        package='.'.join(root.split(sep)[len_root_path:])
        yield root,package
        for f in filter(lambda i : i.endswith('.py') and i != '__init__.py',files):
            (m,ext)=os.path.splitext(f)
            yield os.path.join(root,f),'.'.join([package,m])

def get_module(frame=None,convert=False):

    if frame is None:
        frame=currentframe()
    name=frame.f_globals['__name__']
    return name



def get_subclasses(cls):
    subcls=cls.__subclasses__()
    for i in cls.__subclasses__():
        subcls+=get_subclasses(i)
    return subcls



def detect_module():
    '''
        Detect module
    '''
    frame=currentframe()
    for i in ('__name__','__file__'):
        print(i,frame.f_globals[i])

def filter_list(left,right):
    import collections

    assert(isinstance(left,collections.Iterable)),type(left)
    assert(isinstance(right,collections.Iterable)),type(right)
    same=list(filter(lambda d: d  in left,right))
    return same,list(filter(lambda d: d not in same,left)),list(filter(lambda d: d not in same,right))


class Singleton(object):
    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
        return cls._instance
import types,inspect

def get_qualname(obj):
    m=inspect.getmodule(obj).__name__.split('.')
    members=dir(obj)
    name=getattr(obj,'__qualname__',None) or \
        getattr(obj,'__name__',None)
    if name is None and hasattr(obj,'__class__'):
        name=obj.__class__.__qualname__

    if name is None:
        raise NotImplementedError(str(obj) +' '+ ' has no qualname support' )
    m.append(name)
    return '.'.join(m)



import yaml
from collections import OrderedDict

def yaml_load(stream, loader=yaml.Loader, object_pairs_hook=OrderedDict):
    """
    Custom yaml loader.

    Make all YAML dictionaries load as ordered Dicts.
    http://stackoverflow.com/a/21912744/3609487

    Load all strings as unicode.
    http://stackoverflow.com/a/2967461/3609487
    """

    def construct_mapping(loader, node):
        """Convert to ordered dict."""

        loader.flatten_mapping(node)
        return object_pairs_hook(loader.construct_pairs(node))

    def construct_yaml_str(self, node):
        """Override the default string handling function to always return unicode objects."""

        return self.construct_scalar(node)

    class Loader(loader):
        """Custom Loader."""

    Loader.add_constructor(
        yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
        construct_mapping
    )

    Loader.add_constructor(
        'tag:yaml.org,2002:str',
        construct_yaml_str
    )

    return yaml.load(stream, Loader)

